package lvm.struct;

import lvm.Contexte;
import lvm.LvmException;
import lvm.fonctions.eval.Expr;
import lvm.fonctions.prim.Primitive;

public class Scons implements Liste {
	private Sexpr car;
	private Sexpr cdr;

	/**
	 * Construit un Scons à partir de deux Sexpr
	 * 
	 * @param car: le car du Scons
	 * @param cdr: le cdr du Scons
	 */
	public Scons(Sexpr car, Sexpr cdr) {
		this.car = car;
		this.cdr = cdr;
	}

	/**
	 * Evalue le Scons
	 * 
	 * @return le résultat de l'évaluation
	 * @throws LvmException
	 */
	public Sexpr eval() throws LvmException {
		Primitive p;
		Expr e;
		if (getCar() instanceof Symbole) {
			p = Contexte.getContexteCourant().getPrimitive((Symbole)getCar());
			// Si le CAR n'est une fonction du contexte
			if (p instanceof Primitive)
					return p.exec(getCdr());
			e = Contexte.getContexteCourant().getExpr((Symbole)getCar());
			if (e instanceof Expr)
				return e.exec(getCdr());
			
		}
		
		throw new LvmException("Fonction inconnue : "+getCar().toString());	
	}

	/**
	 * @return le CAR du Scons
	 */
	public Sexpr getCar() {
		return car;
	}

	/**
	 * @return le CDR du Scons
	 */
	public Sexpr getCdr() {
		return cdr;
	}

	/**
	 * @return la représentation textuelle (CAR . (CDR)) du Scons
	 */
	public String toString() {
		if (this.cdr instanceof Nil)
			return "( " + this.car.toString() + " )";
		return "( " + this.car.toString() + " . " + this.cdr.toString() + " )";
	}

	public boolean equals(Sexpr arg) throws LvmException {
		return (arg.getCar().equals(getCar()) && arg.getCdr().equals(getCdr()));
	}
}
